package com.ruoyi.dm.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.constant.CollectFileTypeConstants;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.enums.CollectFileStatusEnum;
import com.ruoyi.common.exception.DataRepeatException;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.biz.BizModule;
import com.ruoyi.common.utils.biz.PathUtil;
import com.ruoyi.dm.component.AnalysisStrategyManager;
import com.ruoyi.dm.component.DataStrategyManager;
import com.ruoyi.dm.domain.AirCollectVO;
import com.ruoyi.dm.domain.CollectEstimateVO;
import com.ruoyi.dm.domain.CollectQueryParam;
import com.ruoyi.dm.domain.po.AirCollectRecordPO;
import com.ruoyi.dm.mapper.AirCollectRecordMapper;
import com.ruoyi.dm.service.IAirCollectRecordService;
import com.ruoyi.system.service.ISysDictDataService;
import com.ruoyi.utils.TranferUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AirCollectRecordServiceImpl extends ServiceImpl<AirCollectRecordMapper, AirCollectRecordPO> implements IAirCollectRecordService {
    @Autowired
    private IAirCollectRecordService airCollectRecordService;

    @Autowired
    private AnalysisStrategyManager analysisStrategyManager;

    @Autowired
    private DataStrategyManager dataStrategyManager;

    @Autowired
    private AirCollectRecordMapper airCollectRecordMapper;

    @Autowired
    private ISysDictDataService sysDictDataService;

    @Override
    public IPage query(CollectQueryParam queryParam) {
        LambdaQueryWrapper<AirCollectRecordPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.hasLength(queryParam.getFileName()),AirCollectRecordPO::getFileName,queryParam.getFileName());
        queryWrapper.eq(StringUtils.hasLength(queryParam.getSatellite()),AirCollectRecordPO::getSatellite,queryParam.getSatellite());
        queryWrapper.eq(StringUtils.hasLength(queryParam.getFileType()),AirCollectRecordPO::getFileType,queryParam.getFileType());
        queryWrapper.eq(StringUtils.hasLength(queryParam.getStatus()), AirCollectRecordPO::getStatus,queryParam.getStatus());
        queryWrapper.eq(StringUtils.hasLength(queryParam.getDataType()), AirCollectRecordPO::getDataType,queryParam.getDataType());
        queryWrapper.eq(null != queryParam.getTrack() , AirCollectRecordPO::getTrack,queryParam.getTrack());
        queryWrapper.orderByDesc(AirCollectRecordPO::getFileDate);
        queryWrapper.between(null != queryParam.getStartTime() && null!= queryParam.getEndTime(),AirCollectRecordPO::getFileDate,queryParam.getStartTime(),queryParam.getEndTime());
        IPage page = airCollectRecordService.page(queryParam.page(), queryWrapper);
        List<SysDictData> satellites = sysDictDataService.listAllSatellite();
        Map<String, List<SysDictData>> collect = satellites.stream().collect(Collectors.groupingBy(SysDictData::getDictValue));
        List<AirCollectVO> objects = new ArrayList<>();
        for (Object airCollectRecordPO : page.getRecords()) {
            AirCollectRecordPO po = (AirCollectRecordPO) airCollectRecordPO;
            AirCollectVO airCollectVO = TranferUtils.tranferAirRecordPO(po);
            //卫星 编码 转名字
            String name = collect.get(airCollectVO.getSatellite()).get(0).getDictLabel();
            airCollectVO.setSatellite(name);
            objects.add(airCollectVO);
        }
        page.setRecords(objects);
        return page;
    }

    @Override
    public IPage queryStation(CollectQueryParam queryParam) {
        LambdaQueryWrapper<AirCollectRecordPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.hasLength(queryParam.getFileName()),AirCollectRecordPO::getFileName,queryParam.getFileName());
        queryWrapper.eq(StringUtils.hasLength(queryParam.getSatellite()),AirCollectRecordPO::getSatellite,queryParam.getSatellite());
        queryWrapper.eq(StringUtils.hasLength(queryParam.getFileType()),AirCollectRecordPO::getFileType,queryParam.getFileType());
        queryWrapper.eq(StringUtils.hasLength(queryParam.getStatus()), AirCollectRecordPO::getStatus,queryParam.getStatus());
        queryWrapper.eq(StringUtils.hasLength(queryParam.getDataType()), AirCollectRecordPO::getDataType,queryParam.getDataType());
        queryWrapper.eq(null != queryParam.getTrack() , AirCollectRecordPO::getTrack,queryParam.getTrack());
        queryWrapper.in(!StringUtils.hasLength(queryParam.getSatellite()) , AirCollectRecordPO::getSatellite,"SWARMA","SWARMB","SWARMC");
        queryWrapper.orderByDesc(AirCollectRecordPO::getFileDate);
        queryWrapper.between(null != queryParam.getStartTime() && null!= queryParam.getEndTime(),AirCollectRecordPO::getFileDate,queryParam.getStartTime(),queryParam.getEndTime());
        IPage page = airCollectRecordService.page(queryParam.page(), queryWrapper);
        List<SysDictData> satellites = sysDictDataService.listAllSatellite();
        Map<String, List<SysDictData>> collect = satellites.stream().collect(Collectors.groupingBy(SysDictData::getDictValue));
        List<AirCollectVO> objects = new ArrayList<>();
        for (Object airCollectRecordPO : page.getRecords()) {
            AirCollectRecordPO po = (AirCollectRecordPO) airCollectRecordPO;
            AirCollectVO airCollectVO = TranferUtils.tranferAirRecordPO(po);
            //卫星 编码 转名字
            String name = collect.get(airCollectVO.getSatellite()).get(0).getDictLabel();
            airCollectVO.setSatellite(name);
            objects.add(airCollectVO);
        }
        page.setRecords(objects);
        return page;
    }

    @Override
    public List<String> uploadFile(MultipartFile[] files, String satellite, String type, String dateType) throws DataRepeatException {
        List<AirCollectRecordPO> list = new ArrayList<>(files.length);
        Date now = new Date();
        String midPath = "";
        if ("FY3C".equals(satellite)) {
            //  /origin/FY3C
            midPath = "/origin/FY3C";
        }else {
            midPath = "/air/"+type+"/"+satellite;
        }
        String fullPath = PathUtil.outputModuleDir(BizModule.COLLECT)+midPath;

        //单个文件,如果重复,直接抛异常
        if (files.length==1) {
            String filename = files[0].getOriginalFilename();
            int num = airCollectRecordService.checkRepeat(filename);
            if (num>0) {
                //存在 不处理
                throw new DataRepeatException();
            }
        }
        List<String> resList = new ArrayList<>();
        for (MultipartFile file : files) {
            String filename = file.getOriginalFilename();
            //根据文件名除重
            int num = airCollectRecordService.checkRepeat(filename);
            if (num > 0) {
                resList.add(filename);
                continue;
            }
            AirCollectRecordPO airCollectRecordPO = new AirCollectRecordPO();
            airCollectRecordPO.setFileName(filename);
            airCollectRecordPO.setFileType(type);
            airCollectRecordPO.setSatellite(satellite);
            airCollectRecordPO.setFileSize(file.getSize());
            airCollectRecordPO.setUploadTime(now);
            airCollectRecordPO.setFilePath(midPath);
            airCollectRecordPO.setStatus(CollectFileStatusEnum.FILE_WAIT.getCode());
            //风场 的 timed 不从页面获取,从文件名获取
            airCollectRecordPO.setDataType(dateType);
            File parentPath = new File(fullPath);
            try {
                if (!parentPath.exists()) {
                    parentPath.mkdirs();
                }
                File path = new File(fullPath, filename);
                file.transferTo(path);
                //通过filename 获取 信息
                //选择数据策略,并进行相应的的特殊化处理
                dataStrategyManager.switchStrategy(type,satellite,dateType).makeupPo(airCollectRecordPO);
                log.info("文件:{} 上传完成",path );
            }catch (Exception e) {
                log.error("文件保存异常",e);
                airCollectRecordPO.setStatus(CollectFileStatusEnum.FILE_ERROR.getCode());
                airCollectRecordPO.setFileDesc("保存异常，"+e.getMessage());
            }

            list.add(airCollectRecordPO);
        }
        //保存到数据库
        airCollectRecordService.saveBatch(list);
        for (AirCollectRecordPO po : list) {
            analysisStrategyManager.analysisAir(po, null);
        }
        return resList;
    }


    @Override
    public boolean delFile(Long id) {
        LambdaQueryWrapper<AirCollectRecordPO> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(AirCollectRecordPO::getFilePath,AirCollectRecordPO::getFileName);
        wrapper.eq(AirCollectRecordPO::getId,id);
        AirCollectRecordPO po = airCollectRecordService.getOne(wrapper);
        String fullPath = PathUtil.outputModuleDir(BizModule.COLLECT)+po.getFilePath()+"/"+ po.getFileName();
        new File(fullPath).delete();
        return airCollectRecordService.removeById(id);
    }

    @Override
    public boolean delBatch(Long[] delParam) {
        LambdaQueryWrapper<AirCollectRecordPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(AirCollectRecordPO::getId,delParam);
        queryWrapper.select(AirCollectRecordPO::getFilePath,AirCollectRecordPO::getFileName);
        List<AirCollectRecordPO> pos = airCollectRecordService.list(queryWrapper);
        if (null != pos) {
            for (AirCollectRecordPO po : pos) {
                String fullPath = PathUtil.outputModuleDir(BizModule.COLLECT)+po.getFilePath()+"/"+ po.getFileName();
                new File(fullPath).delete();
            }
        }
        return airCollectRecordService.remove(queryWrapper);
    }

    @Override
    public String download(Long id) {
        LambdaQueryWrapper<AirCollectRecordPO> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(AirCollectRecordPO::getFilePath,AirCollectRecordPO::getFileName);
        wrapper.eq(AirCollectRecordPO::getId,id);
        AirCollectRecordPO po = airCollectRecordService.getOne(wrapper);
        String fullPath = PathUtil.outputModuleDir(BizModule.COLLECT);
        return fullPath+po.getFilePath()+"/"+ po.getFileName();
    }

    @Override
    public String downloadBatch(Long[] ids) {
        LambdaQueryWrapper<AirCollectRecordPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(AirCollectRecordPO::getId,ids);
        List<AirCollectRecordPO> list = airCollectRecordService.list(queryWrapper);
        String path = PathUtil.tmpModuleDir(BizModule.COLLECT)+"/"+DateUtil.format(new Date(),"yyyyMMddHHmmss")+".zip";
        if (CollectionUtil.isNotEmpty(list)) {
            File[] toZipArr = new File[list.size()];
            for (int i = 0; i < list.size(); i++) {
                String fullPath = PathUtil.outputModuleDir(BizModule.COLLECT)+list.get(i).getFilePath()+"/"+list.get(i).getFileName();
                toZipArr[i] = new File(fullPath);
            }
            ZipUtil.zip(new File(path), false, toZipArr);
        }
        return path;
    }

    @Override
    public boolean analysis(Long id, String method) {
        LambdaQueryWrapper<AirCollectRecordPO> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(AirCollectRecordPO::getId,AirCollectRecordPO::getFilePath,AirCollectRecordPO::getFileName,AirCollectRecordPO::getFileType,AirCollectRecordPO::getSatellite,AirCollectRecordPO::getDataType);
        wrapper.eq(AirCollectRecordPO::getId,id);
        AirCollectRecordPO po = airCollectRecordService.getOne(wrapper);
        if (null != po && CollectFileStatusEnum.FILE_SUCC.getCode() == po.getStatus()) {
            throw new ServiceException("请勿重复解析");
        }
        LambdaUpdateWrapper<AirCollectRecordPO> uw = new LambdaUpdateWrapper<>();
        uw.eq(AirCollectRecordPO::getId,id);
        uw.set(AirCollectRecordPO::getStatus,CollectFileStatusEnum.FILE_WAIT.getCode());
        airCollectRecordService.update(uw);
        analysisStrategyManager.analysisAir(po,method);
        return true;
    }

    @Override
    public boolean analysisBatch(Long[] ids, String method) {
        LambdaQueryWrapper<AirCollectRecordPO> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(AirCollectRecordPO::getId,AirCollectRecordPO::getStatus,AirCollectRecordPO::getFilePath,AirCollectRecordPO::getFileName,AirCollectRecordPO::getFileType,AirCollectRecordPO::getSatellite,AirCollectRecordPO::getDataType);
        wrapper.in(AirCollectRecordPO::getId,ids);
        List<AirCollectRecordPO> list = airCollectRecordService.list(wrapper);
        if (CollectionUtil.isNotEmpty(list)) {
            List<Long> ids4Analysis = new ArrayList<>();
            //已解析的不再处理
            ArrayList<String> finishedList = new ArrayList<>();
            for (AirCollectRecordPO po : list) {
                if ( CollectFileStatusEnum.FILE_SUCC.getCode() == po.getStatus()) {
                    finishedList.add(po.getFileName());
                }else {
                    ids4Analysis.add(po.getId());
                }
            }
            if (CollectionUtil.isNotEmpty(ids4Analysis)) {
                LambdaUpdateWrapper<AirCollectRecordPO> uw = new LambdaUpdateWrapper<>();
                uw.in(AirCollectRecordPO::getId, ids4Analysis);
                uw.set(AirCollectRecordPO::getStatus, CollectFileStatusEnum.FILE_WAIT.getCode());
                airCollectRecordService.update(uw);
                for (AirCollectRecordPO po : list) {
                    if ( CollectFileStatusEnum.FILE_SUCC.getCode() == po.getStatus()) {
                        continue;
                    }else {
                        analysisStrategyManager.analysisAir(po, method);
                    }
                }
            }
            if (CollectionUtil.isNotEmpty(finishedList)) {
                throw new ServiceException("重复数据不再解析:"+CollectionUtil.join(finishedList,","));
            }

        }
        return true;
    }

    @Override
    public String lookDetailRes(Long id) throws Exception {
        LambdaQueryWrapper<AirCollectRecordPO> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(AirCollectRecordPO::getResFile,AirCollectRecordPO::getFileType);
        wrapper.eq(AirCollectRecordPO::getId,id);
        AirCollectRecordPO po = airCollectRecordService.getOne(wrapper);
        if (null != po && StringUtils.hasLength(po.getResFile())) {
            JSONObject jsonObject = JSON.parseObject(po.getResFile());
            String logFile = jsonObject.getString("logFile");
            if (CollectFileTypeConstants.TYPE_DEN.equals(po.getFileType())) {
                //大气密度 详情分了多个文件
                File file = new File(logFile);
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.append(FileUtil.readString(logFile,Charset.forName("UTF-8")));
                File parentFile = file.getParentFile().getParentFile();
                //error_by_altitude.txt
                stringBuilder.append("\n").append("-----------------------------------------------------").append("\n");
                stringBuilder.append("纬度错误数据").append("\n");
                try {
                    stringBuilder.append(FileUtil.readString(new File(parentFile, "error_by_altitude.txt"), Charset.forName("UTF-8")));
                }catch (Exception e) {
                    //
                }
                //error_by_density.txt
                stringBuilder.append("-----------------------------------------------------").append("\n");
                stringBuilder.append("密度错误数据").append("\n");
                try {
                    stringBuilder.append(FileUtil.readString(new File(parentFile, "error_by_density.txt"), Charset.forName("UTF-8")));
                }catch (Exception e) {

                }
                //error_by_latlon.txt
                stringBuilder.append("-----------------------------------------------------").append("\n");
                stringBuilder.append("经纬度坐标错误数据").append("\n");
                try {
                    stringBuilder.append(FileUtil.readString(new File(parentFile, "error_by_latlon.txt"), Charset.forName("UTF-8")));
                }catch (Exception e) {

                }
                //error_by_time.txt
                stringBuilder.append("-----------------------------------------------------").append("\n");
                stringBuilder.append("时间错误数据").append("\n");
                try {
                    stringBuilder.append(FileUtil.readString(new File(parentFile, "error_by_time.txt"), Charset.forName("UTF-8")));
                }catch (Exception e) {

                }
                return stringBuilder.toString();
            }else {
                String content = FileUtil.readString(logFile,Charset.forName("UTF-8"));
                return content;
            }

        }else {
            throw  new Exception("数据不存在或解析异常");
        }
    }

    @Override
    public int checkRepeat(String filename) {
        return airCollectRecordMapper.selectRepeat(filename);
    }

    @Override
    public CollectEstimateVO lookRes(Long id) throws Exception {
        LambdaQueryWrapper<AirCollectRecordPO> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(AirCollectRecordPO::getResFile);
        wrapper.eq(AirCollectRecordPO::getId,id);
        AirCollectRecordPO po = airCollectRecordService.getOne(wrapper);
        if (null != po && StringUtils.hasLength(po.getResFile())) {
            JSONObject jsonObject = JSON.parseObject(po.getResFile());
            CollectEstimateVO collectEstimateVO = new CollectEstimateVO();
            collectEstimateVO.setToal(jsonObject.getInteger("total"));
            collectEstimateVO.setError(jsonObject.getInteger("error"));
            return collectEstimateVO;
        }else {
            throw  new Exception("数据不存在或解析异常");
        }
    }


}
